home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / g_misc.c1 < prev    next >
Encoding:
Text File  |  2002-12-26  |  51.5 KB  |  2,134 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // g_misc.c
  21.  
  22. #include "g_local.h"
  23.  
  24.  
  25. /*QUAKED func_group (0 0 0) ?
  26. Used to group brushes together just for editor convenience.
  27. */
  28.  
  29. //=====================================================
  30.  
  31. void Use_Areaportal (edict_t *ent, edict_t *other, edict_t *activator)
  32. {
  33.     ent->count ^= 1;        // toggle state
  34. //    gi.dprintf ("portalstate: %i = %i\n", ent->style, ent->count);
  35.     gi.SetAreaPortalState (ent->style, ent->count);
  36. }
  37.  
  38. /*QUAKED func_areaportal (0 0 0) ?
  39.  
  40. This is a non-visible object that divides the world into
  41. areas that are seperated when this portal is not activated.
  42. Usually enclosed in the middle of a door.
  43. */
  44. void SP_func_areaportal (edict_t *ent)
  45. {
  46.     ent->use = Use_Areaportal;
  47.     ent->count = 0;        // always start closed;
  48. }
  49.  
  50. //=====================================================
  51.  
  52.  
  53. /*
  54. =================
  55. Misc functions
  56. =================
  57. */
  58. void VelocityForDamage (int damage, vec3_t v)
  59. {
  60.     v[0] = 100.0 * crandom();
  61.     v[1] = 100.0 * crandom();
  62.     v[2] = 200.0 + 100.0 * random();
  63.  
  64.     if (damage < 50)
  65.         VectorScale (v, 0.7, v);
  66.     else 
  67.         VectorScale (v, 1.2, v);
  68. }
  69.  
  70. void ClipGibVelocity (edict_t *ent)
  71. {
  72.     if (ent->velocity[0] < -300)
  73.         ent->velocity[0] = -300;
  74.     else if (ent->velocity[0] > 300)
  75.         ent->velocity[0] = 300;
  76.     if (ent->velocity[1] < -300)
  77.         ent->velocity[1] = -300;
  78.     else if (ent->velocity[1] > 300)
  79.         ent->velocity[1] = 300;
  80.     if (ent->velocity[2] < 200)
  81.         ent->velocity[2] = 200;    // always some upwards
  82.     else if (ent->velocity[2] > 500)
  83.         ent->velocity[2] = 500;
  84. }
  85.  
  86.  
  87. /*
  88. =================
  89. gibs
  90. =================
  91. */
  92. void gib_think (edict_t *self)
  93. {
  94.     self->s.frame++;
  95.     self->nextthink = level.time + FRAMETIME;
  96.  
  97.     if (self->s.frame == 10)
  98.     {
  99.         self->think = G_FreeEdict;
  100.         self->nextthink = level.time + 8 + random()*10;
  101.     }
  102. }
  103.  
  104. void gib_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  105. {
  106.     vec3_t    normal_angles, right;
  107.  
  108.     if (!self->groundentity)
  109.         return;
  110.  
  111.     self->touch = NULL;
  112.  
  113.     if (plane)
  114.     {
  115.         gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/fhit3.wav"), 1, ATTN_NORM, 0);
  116.  
  117.         vectoangles (plane->normal, normal_angles);
  118.         AngleVectors (normal_angles, NULL, right, NULL);
  119.         vectoangles (right, self->s.angles);
  120.  
  121.         if (self->s.modelindex == sm_meat_index)
  122.         {
  123.             self->s.frame++;
  124.             self->think = gib_think;
  125.             self->nextthink = level.time + FRAMETIME;
  126.         }
  127.     }
  128. }
  129.  
  130. void gib_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  131. {
  132.     G_FreeEdict (self);
  133. }
  134.  
  135. void ThrowGib (edict_t *self, char *gibname, int damage, int type, int effects)
  136. {
  137.     edict_t *gib;
  138.     vec3_t    vd;
  139.     vec3_t    origin;
  140.     vec3_t    size;
  141.     float    vscale;
  142.  
  143.     gib = G_Spawn();
  144.  
  145.     VectorScale (self->size, 0.5, size);
  146.     VectorAdd (self->absmin, size, origin);
  147.     gib->s.origin[0] = origin[0] + crandom() * size[0];
  148.     gib->s.origin[1] = origin[1] + crandom() * size[1];
  149.     gib->s.origin[2] = origin[2] + crandom() * size[2];
  150.  
  151.     gi.setmodel (gib, gibname);
  152.     gib->solid = SOLID_NOT;
  153.     gib->s.effects = effects;
  154.     gib->flags |= FL_NO_KNOCKBACK;
  155.     gib->takedamage = DAMAGE_YES;
  156.     gib->die = gib_die;
  157.  
  158.     if (type == GIB_ORGANIC)
  159.     {
  160.         gib->movetype = MOVETYPE_TOSS;
  161.         gib->touch = gib_touch;
  162.         vscale = 0.5;
  163.     }
  164.     else
  165.     {
  166.         gib->movetype = MOVETYPE_BOUNCE;
  167.         vscale = 1.0;
  168.     }
  169.  
  170.     VelocityForDamage (damage, vd);
  171.     VectorMA (self->velocity, vscale, vd, gib->velocity);
  172.     ClipGibVelocity (gib);
  173.     gib->avelocity[0] = random()*600;
  174.     gib->avelocity[1] = random()*600;
  175.     gib->avelocity[2] = random()*600;
  176.  
  177.     gib->think = G_FreeEdict;
  178.     gib->nextthink = level.time + 10 + random()*10;
  179.  
  180.     gi.linkentity (gib);
  181. }
  182.  
  183. void ThrowBloodStain (edict_t *self, char *gibname)
  184. {
  185.     edict_t *blood;
  186.  
  187.     blood = G_Spawn();
  188.  
  189.     blood->s.origin[0] = self->s.origin[0];
  190.     blood->s.origin[1] = self->s.origin[1];
  191.     blood->s.origin[2] = self->s.origin[2] - 16;
  192.  
  193.     gi.setmodel (blood, gibname);
  194.     blood->solid = SOLID_NOT;
  195.     
  196.     blood->takedamage = DAMAGE_NO;
  197.     blood->die = gib_die;
  198.  
  199.     blood->movetype = MOVETYPE_NONE;
  200.     
  201.     blood->think = G_FreeEdict;
  202.     blood->nextthink = level.time + 10 + random()*10;
  203.  
  204.     gi.linkentity (blood);
  205. }
  206.  
  207. void ThrowHead (edict_t *self, char *gibname, int damage, int type, int effects)
  208. {
  209.     vec3_t    vd;
  210.     float    vscale;
  211.  
  212.     self->s.skinnum = 0;
  213.     self->s.frame = 0;
  214.     VectorClear (self->mins);
  215.     VectorClear (self->maxs);
  216.  
  217.     self->s.modelindex2 = 0;
  218.     gi.setmodel (self, gibname);
  219.     self->solid = SOLID_NOT;
  220.     self->s.effects = effects;
  221.     self->s.effects &= ~EF_FLIES;
  222.     self->s.sound = 0;
  223.     self->flags |= FL_NO_KNOCKBACK;
  224.     self->svflags &= ~SVF_MONSTER;
  225.     self->takedamage = DAMAGE_YES;
  226.     self->die = gib_die;
  227.  
  228.     if (type == GIB_ORGANIC)
  229.     {
  230.         self->movetype = MOVETYPE_TOSS;
  231.         self->touch = gib_touch;
  232.         vscale = 0.5;
  233.     }
  234.     else
  235.     {
  236.         self->movetype = MOVETYPE_BOUNCE;
  237.         vscale = 1.0;
  238.     }
  239.  
  240.     VelocityForDamage (damage, vd);
  241.     VectorMA (self->velocity, vscale, vd, self->velocity);
  242.     ClipGibVelocity (self);
  243.  
  244.     self->avelocity[YAW] = crandom()*600;
  245.  
  246.     self->think = G_FreeEdict;
  247.     self->nextthink = level.time + 10 + random()*10;
  248.  
  249.     gi.linkentity (self);
  250. }
  251.  
  252. void ThrowClientHead (edict_t *self, int damage)
  253. {
  254.     vec3_t    vd;
  255.     char    *gibname;
  256.  
  257.     if (rand()&1)
  258.     {
  259.         gibname = "models/objects/gibs/sm_meat/tris.md2";
  260.         self->s.skinnum = 0;        // second skin is player
  261.     }
  262.     else
  263.     {
  264.         gibname = "models/objects/gibs/sm_meat/tris.md2";
  265.         self->s.skinnum = 0;
  266.     }
  267.  
  268.     self->s.origin[2] += 32;
  269.     self->s.frame = 0;
  270.     gi.setmodel (self, gibname);
  271.     VectorSet (self->mins, -16, -16, 0);
  272.     VectorSet (self->maxs, 16, 16, 16);
  273.  
  274.     self->takedamage = DAMAGE_NO;
  275.     self->solid = SOLID_NOT;
  276.     self->s.effects = EF_GIB;
  277.     self->s.sound = 0;
  278.     self->flags |= FL_NO_KNOCKBACK;
  279.  
  280.     self->movetype = MOVETYPE_BOUNCE;
  281.     VelocityForDamage (damage, vd);
  282.     VectorAdd (self->velocity, vd, self->velocity);
  283.  
  284.     if (self->client)    // bodies in the queue don't have a client anymore
  285.     {
  286.         self->client->anim_priority = ANIM_DEATH;
  287.         self->client->anim_end = self->s.frame;
  288.     }
  289.     else
  290.     {
  291.         self->think = NULL;
  292.         self->nextthink = 0;
  293.     }
  294.  
  295.     gi.linkentity (self);
  296. }
  297.  
  298.  
  299. /*
  300. =================
  301. debris
  302. =================
  303. */
  304. void debris_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  305. {
  306.     G_FreeEdict (self);
  307. }
  308.  
  309. void ThrowDebris (edict_t *self, char *modelname, float speed, vec3_t origin)
  310. {
  311.     edict_t    *chunk;
  312.     vec3_t    v;
  313.  
  314.     chunk = G_Spawn();
  315.     VectorCopy (origin, chunk->s.origin);
  316.     gi.setmodel (chunk, modelname);
  317.     v[0] = 100 * crandom();
  318.     v[1] = 100 * crandom();
  319.     v[2] = 100 + 100 * crandom();
  320.     VectorMA (self->velocity, speed, v, chunk->velocity);
  321.     chunk->movetype = MOVETYPE_BOUNCE;
  322.     chunk->solid = SOLID_NOT;
  323.     chunk->avelocity[0] = random()*600;
  324.     chunk->avelocity[1] = random()*600;
  325.     chunk->avelocity[2] = random()*600;
  326.     chunk->think = G_FreeEdict;
  327.     chunk->nextthink = level.time + 5 + random()*5;
  328.     chunk->s.frame = 0;
  329.     chunk->flags = 0;
  330.     chunk->classname = "debris";
  331.     chunk->takedamage = DAMAGE_YES;
  332.     chunk->die = debris_die;
  333.     gi.linkentity (chunk);
  334. }
  335.  
  336.  
  337. void BecomeExplosion1 (edict_t *self)
  338. {
  339.     gi.WriteByte (svc_temp_entity);
  340.     gi.WriteByte (TE_EXPLOSION1);
  341.     gi.WritePosition (self->s.origin);
  342.     gi.multicast (self->s.origin, MULTICAST_PVS);
  343.  
  344.     G_FreeEdict (self);
  345. }
  346.  
  347.  
  348. void BecomeExplosion2 (edict_t *self)
  349. {
  350.     gi.WriteByte (svc_temp_entity);
  351.     gi.WriteByte (TE_EXPLOSION2);
  352.     gi.WritePosition (self->s.origin);
  353.     gi.multicast (self->s.origin, MULTICAST_PVS);
  354.  
  355.     G_FreeEdict (self);
  356. }
  357.  
  358.  
  359. /*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8) TELEPORT
  360. Target: next path corner
  361. Pathtarget: gets used when an entity that has
  362.     this path_corner targeted touches it
  363. */
  364.  
  365. void path_corner_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  366. {
  367.     vec3_t        v;
  368.     edict_t        *next;
  369.  
  370.     if (other->movetarget != self)
  371.         return;
  372.     
  373.     if (other->enemy)
  374.         return;
  375.  
  376.     if (self->pathtarget)
  377.     {
  378.         char *savetarget;
  379.  
  380.         savetarget = self->target;
  381.         self->target = self->pathtarget;
  382.         G_UseTargets (self, other);
  383.         self->target = savetarget;
  384.     }
  385.  
  386.     if (self->target)
  387.         next = G_PickTarget(self->target);
  388.     else
  389.         next = NULL;
  390.  
  391.     if ((next) && (next->spawnflags & 1))
  392.     {
  393.         VectorCopy (next->s.origin, v);
  394.         v[2] += next->mins[2];
  395.         v[2] -= other->mins[2];
  396.         VectorCopy (v, other->s.origin);
  397.         next = G_PickTarget(next->target);
  398.         other->s.event = EV_OTHER_TELEPORT;
  399.     }
  400.  
  401.     other->goalentity = other->movetarget = next;
  402.  
  403.     if (self->wait)
  404.     {
  405.         other->monsterinfo.pausetime = level.time + self->wait;
  406.         other->monsterinfo.stand (other);
  407.         return;
  408.     }
  409.  
  410.     if (!other->movetarget)
  411.     {
  412.         other->monsterinfo.pausetime = level.time + 100000000;
  413.         other->monsterinfo.stand (other);
  414.     }
  415.     else
  416.     {
  417.         VectorSubtract (other->goalentity->s.origin, other->s.origin, v);
  418.         other->ideal_yaw = vectoyaw (v);
  419.     }
  420. }
  421.  
  422. void SP_path_corner (edict_t *self)
  423. {
  424.     if (!self->targetname)
  425.     {
  426.         gi.dprintf ("path_corner with no targetname at %s\n", vtos(self->s.origin));
  427.         G_FreeEdict (self);
  428.         return;
  429.     }
  430.  
  431.     self->solid = SOLID_TRIGGER;
  432.     self->touch = path_corner_touch;
  433.     VectorSet (self->mins, -8, -8, -8);
  434.     VectorSet (self->maxs, 8, 8, 8);
  435.     self->svflags |= SVF_NOCLIENT;
  436.     gi.linkentity (self);
  437. }
  438.  
  439.  
  440. /*QUAKED point_combat (0.5 0.3 0) (-8 -8 -8) (8 8 8) Hold
  441. Makes this the target of a monster and it will head here
  442. when first activated before going after the activator.  If
  443. hold is selected, it will stay here.
  444. */
  445. void point_combat_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  446. {
  447.     edict_t    *activator;
  448.  
  449.     if (other->movetarget != self)
  450.         return;
  451.  
  452.     if (self->target)
  453.     {
  454.         other->target = self->target;
  455.         other->goalentity = other->movetarget = G_PickTarget(other->target);
  456.         if (!other->goalentity)
  457.         {
  458.             gi.dprintf("%s at %s target %s does not exist\n", self->classname, vtos(self->s.origin), self->target);
  459.             other->movetarget = self;
  460.         }
  461.         self->target = NULL;
  462.     }
  463.     else if ((self->spawnflags & 1) && !(other->flags & (FL_SWIM|FL_FLY)))
  464.     {
  465.         other->monsterinfo.pausetime = level.time + 100000000;
  466.         other->monsterinfo.aiflags |= AI_STAND_GROUND;
  467.         other->monsterinfo.stand (other);
  468.     }
  469.  
  470.     if (other->movetarget == self)
  471.     {
  472.         other->target = NULL;
  473.         other->movetarget = NULL;
  474.         other->goalentity = other->enemy;
  475.         other->monsterinfo.aiflags &= ~AI_COMBAT_POINT;
  476.     }
  477.  
  478.     if (self->pathtarget)
  479.     {
  480.         char *savetarget;
  481.  
  482.         savetarget = self->target;
  483.         self->target = self->pathtarget;
  484.         if (other->enemy && other->enemy->client)
  485.             activator = other->enemy;
  486.         else if (other->oldenemy && other->oldenemy->client)
  487.             activator = other->oldenemy;
  488.         else if (other->activator && other->activator->client)
  489.             activator = other->activator;
  490.         else
  491.             activator = other;
  492.         G_UseTargets (self, activator);
  493.         self->target = savetarget;
  494.     }
  495. }
  496.  
  497. void SP_point_combat (edict_t *self)
  498. {
  499.     if (deathmatch->value)
  500.     {
  501.         G_FreeEdict (self);
  502.         return;
  503.     }
  504.     self->solid = SOLID_TRIGGER;
  505.     self->touch = point_combat_touch;
  506.     VectorSet (self->mins, -8, -8, -16);
  507.     VectorSet (self->maxs, 8, 8, 16);
  508.     self->svflags = SVF_NOCLIENT;
  509.     gi.linkentity (self);
  510. };
  511.  
  512.  
  513. /*QUAKED viewthing (0 .5 .8) (-8 -8 -8) (8 8 8)
  514. Just for the debugging level.  Don't use
  515. */
  516. void TH_viewthing(edict_t *ent)
  517. {
  518.     ent->s.frame = (ent->s.frame + 1) % 7;
  519.     ent->nextthink = level.time + FRAMETIME;
  520. }
  521.  
  522. void SP_viewthing(edict_t *ent)
  523. {
  524.     gi.dprintf ("viewthing spawned\n");
  525.  
  526.     ent->movetype = MOVETYPE_NONE;
  527.     ent->solid = SOLID_BBOX;
  528.     ent->s.renderfx = RF_FRAMELERP;
  529.     VectorSet (ent->mins, -16, -16, -24);
  530.     VectorSet (ent->maxs, 16, 16, 32);
  531.     ent->s.modelindex = gi.modelindex ("models/objects/banner/tris.md2");
  532.     gi.linkentity (ent);
  533.     ent->nextthink = level.time + 0.5;
  534.     ent->think = TH_viewthing;
  535.     return;
  536. }
  537.  
  538.  
  539. /*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
  540. Used as a positional target for spotlights, etc.
  541. */
  542. void SP_info_null (edict_t *self)
  543. {
  544.     G_FreeEdict (self);
  545. };
  546.  
  547.  
  548. /*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
  549. Used as a positional target for lightning.
  550. */
  551. void SP_info_notnull (edict_t *self)
  552. {
  553.     VectorCopy (self->s.origin, self->absmin);
  554.     VectorCopy (self->s.origin, self->absmax);
  555. };
  556.  
  557.  
  558. /*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) START_OFF
  559. Non-displayed light.
  560. Default light value is 300.
  561. Default style is 0.
  562. If targeted, will toggle between on and off.
  563. Default _cone value is 10 (used to set size of light for spotlights)
  564. */
  565.  
  566. #define START_OFF    1
  567.  
  568. static void light_use (edict_t *self, edict_t *other, edict_t *activator)
  569. {
  570.     if (self->spawnflags & START_OFF)
  571.     {
  572.         gi.configstring (CS_LIGHTS+self->style, "m");
  573.         self->spawnflags &= ~START_OFF;
  574.     }
  575.     else
  576.     {
  577.         gi.configstring (CS_LIGHTS+self->style, "a");
  578.         self->spawnflags |= START_OFF;
  579.     }
  580. }
  581.  
  582. void SP_light (edict_t *self)
  583. {
  584.     // no targeted lights in deathmatch, because they cause global messages
  585.     if (!self->targetname || deathmatch->value)
  586.     {
  587.         G_FreeEdict (self);
  588.         return;
  589.     }
  590.  
  591.     if (self->style >= 32)
  592.     {
  593.         self->use = light_use;
  594.         if (self->spawnflags & START_OFF)
  595.             gi.configstring (CS_LIGHTS+self->style, "a");
  596.         else
  597.             gi.configstring (CS_LIGHTS+self->style, "m");
  598.     }
  599. }
  600.  
  601.  
  602. /*QUAKED func_wall (0 .5 .8) ? TRIGGER_SPAWN TOGGLE START_ON ANIMATED ANIMATED_FAST
  603. This is just a solid wall if not inhibited
  604.  
  605. TRIGGER_SPAWN    the wall will not be present until triggered
  606.                 it will then blink in to existance; it will
  607.                 kill anything that was in it's way
  608.  
  609. TOGGLE            only valid for TRIGGER_SPAWN walls
  610.                 this allows the wall to be turned on and off
  611.  
  612. START_ON        only valid for TRIGGER_SPAWN walls
  613.                 the wall will initially be present
  614. */
  615.  
  616. void func_wall_use (edict_t *self, edict_t *other, edict_t *activator)
  617. {
  618.     if (self->solid == SOLID_NOT)
  619.     {
  620.         self->solid = SOLID_BSP;
  621.         self->svflags &= ~SVF_NOCLIENT;
  622.         KillBox (self);
  623.     }
  624.     else
  625.     {
  626.         self->solid = SOLID_NOT;
  627.         self->svflags |= SVF_NOCLIENT;
  628.     }
  629.     gi.linkentity (self);
  630.  
  631.     if (!(self->spawnflags & 2))
  632.         self->use = NULL;
  633. }
  634.  
  635. void SP_func_wall (edict_t *self)
  636. {
  637.     self->movetype = MOVETYPE_PUSH;
  638.     gi.setmodel (self, self->model);
  639.  
  640.     if (self->spawnflags & 8)
  641.         self->s.effects |= EF_ANIM_ALL;
  642.     if (self->spawnflags & 16)
  643.         self->s.effects |= EF_ANIM_ALLFAST;
  644.  
  645.     // just a wall
  646.     if ((self->spawnflags & 7) == 0)
  647.     {
  648.         self->solid = SOLID_BSP;
  649.         gi.linkentity (self);
  650.         return;
  651.     }
  652.  
  653.     // it must be TRIGGER_SPAWN
  654.     if (!(self->spawnflags & 1))
  655.     {
  656. //        gi.dprintf("func_wall missing TRIGGER_SPAWN\n");
  657.         self->spawnflags |= 1;
  658.     }
  659.  
  660.     // yell if the spawnflags are odd
  661.     if (self->spawnflags & 4)
  662.     {
  663.         if (!(self->spawnflags & 2))
  664.         {
  665.             gi.dprintf("func_wall START_ON without TOGGLE\n");
  666.             self->spawnflags |= 2;
  667.         }
  668.     }
  669.  
  670.     self->use = func_wall_use;
  671.     if (self->spawnflags & 4)
  672.     {
  673.         self->solid = SOLID_BSP;
  674.     }
  675.     else
  676.     {
  677.         self->solid = SOLID_NOT;
  678.         self->svflags |= SVF_NOCLIENT;
  679.     }
  680.     gi.linkentity (self);
  681. }
  682.  
  683.  
  684. /*QUAKED func_object (0 .5 .8) ? TRIGGER_SPAWN ANIMATED ANIMATED_FAST
  685. This is solid bmodel that will fall if it's support it removed.
  686. */
  687.  
  688. void func_object_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  689. {
  690.     // only squash thing we fall on top of
  691.     if (!plane)
  692.         return;
  693.     if (plane->normal[2] < 1.0)
  694.         return;
  695.     if (other->takedamage == DAMAGE_NO)
  696.         return;
  697.     T_Damage (other, self, self, vec3_origin, self->s.origin, vec3_origin, self->dmg, 1, 0, MOD_CRUSH);
  698. }
  699.  
  700. void func_object_release (edict_t *self)
  701. {
  702.     self->movetype = MOVETYPE_TOSS;
  703.     self->touch = func_object_touch;
  704. }
  705.  
  706. void func_object_use (edict_t *self, edict_t *other, edict_t *activator)
  707. {
  708.     self->solid = SOLID_BSP;
  709.     self->svflags &= ~SVF_NOCLIENT;
  710.     self->use = NULL;
  711.     KillBox (self);
  712.     func_object_release (self);
  713. }
  714.  
  715. void SP_func_object (edict_t *self)
  716. {
  717.     gi.setmodel (self, self->model);
  718.  
  719.     self->mins[0] += 1;
  720.     self->mins[1] += 1;
  721.     self->mins[2] += 1;
  722.     self->maxs[0] -= 1;
  723.     self->maxs[1] -= 1;
  724.     self->maxs[2] -= 1;
  725.  
  726.     if (!self->dmg)
  727.         self->dmg = 100;
  728.  
  729.     if (self->spawnflags == 0)
  730.     {
  731.         self->solid = SOLID_BSP;
  732.         self->movetype = MOVETYPE_PUSH;
  733.         self->think = func_object_release;
  734.         self->nextthink = level.time + 2 * FRAMETIME;
  735.     }
  736.     else
  737.     {
  738.         self->solid = SOLID_NOT;
  739.         self->movetype = MOVETYPE_PUSH;
  740.         self->use = func_object_use;
  741.         self->svflags |= SVF_NOCLIENT;
  742.     }
  743.  
  744.     if (self->spawnflags & 2)
  745.         self->s.effects |= EF_ANIM_ALL;
  746.     if (self->spawnflags & 4)
  747.         self->s.effects |= EF_ANIM_ALLFAST;
  748.  
  749.     self->clipmask = MASK_MONSTERSOLID;
  750.  
  751.     gi.linkentity (self);
  752. }
  753.  
  754.  
  755. /*QUAKED func_explosive (0 .5 .8) ? Trigger_Spawn ANIMATED ANIMATED_FAST
  756. Any brush that you want to explode or break apart.  If you want an
  757. ex0plosion, set dmg and it will do a radius explosion of that amount
  758. at the center of the bursh.
  759.  
  760. If targeted it will not be shootable.
  761.  
  762. health defaults to 100.
  763.  
  764. mass defaults to 75.  This determines how much debris is emitted when
  765. it explodes.  You get one large chunk per 100 of mass (up to 8) and
  766. one small chunk per 25 of mass (up to 16).  So 800 gives the most.
  767. */
  768. void func_explosive_explode (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  769. {
  770.     vec3_t    origin;
  771.     vec3_t    chunkorigin;
  772.     vec3_t    size;
  773.     int        count;
  774.     int        mass;
  775.  
  776.     // bmodel origins are (0 0 0), we need to adjust that here
  777.     VectorScale (self->size, 0.5, size);
  778.     VectorAdd (self->absmin, size, origin);
  779.     VectorCopy (origin, self->s.origin);
  780.  
  781.     self->takedamage = DAMAGE_NO;
  782.  
  783.     if (self->dmg)
  784.         T_RadiusDamage (self, attacker, self->dmg, NULL, self->dmg+40, MOD_EXPLOSIVE);
  785.  
  786.     VectorSubtract (self->s.origin, inflictor->s.origin, self->velocity);
  787.     VectorNormalize (self->velocity);
  788.     VectorScale (self->velocity, 150, self->velocity);
  789.  
  790.     // start chunks towards the center
  791.     VectorScale (size, 0.5, size);
  792.  
  793.     mass = self->mass;
  794.     if (!mass)
  795.         mass = 75;
  796.  
  797.     // big chunks
  798.     if (mass >= 100)
  799.     {
  800.         count = mass / 100;
  801.         if (count > 8)
  802.             count = 8;
  803.         while(count--)
  804.         {
  805.             chunkorigin[0] = origin[0] + crandom() * size[0];
  806.             chunkorigin[1] = origin[1] + crandom() * size[1];
  807.             chunkorigin[2] = origin[2] + crandom() * size[2];
  808.             ThrowDebris (self, "models/objects/debris1/tris.md2", 1, chunkorigin);
  809.         }
  810.     }
  811.  
  812.     // small chunks
  813.     count = mass / 25;
  814.     if (count > 16)
  815.         count = 16;
  816.     while(count--)
  817.     {
  818.         chunkorigin[0] = origin[0] + crandom() * size[0];
  819.         chunkorigin[1] = origin[1] + crandom() * size[1];
  820.         chunkorigin[2] = origin[2] + crandom() * size[2];
  821.         ThrowDebris (self, "models/objects/debris2/tris.md2", 2, chunkorigin);
  822.     }
  823.  
  824.     G_UseTargets (self, attacker);
  825.  
  826.     if (self->dmg)
  827.         BecomeExplosion1 (self);
  828.     else
  829.         G_FreeEdict (self);
  830. }
  831.  
  832. void func_explosive_use(edict_t *self, edict_t *other, edict_t *activator)
  833. {
  834.     func_explosive_explode (self, self, other, self->health, vec3_origin);
  835. }
  836.  
  837. void func_explosive_spawn (edict_t *self, edict_t *other, edict_t *activator)
  838. {
  839.     self->solid = SOLID_BSP;
  840.     self->svflags &= ~SVF_NOCLIENT;
  841.     self->use = NULL;
  842.     KillBox (self);
  843.     gi.linkentity (self);
  844. }
  845.  
  846. void SP_func_explosive (edict_t *self)
  847. {
  848.     if (deathmatch->value)
  849.     {    // auto-remove for deathmatch
  850.         G_FreeEdict (self);
  851.         return;
  852.     }
  853.  
  854.     self->movetype = MOVETYPE_PUSH;
  855.  
  856.     gi.modelindex ("models/objects/debris1/tris.md2");
  857.     gi.modelindex ("models/objects/debris2/tris.md2");
  858.  
  859.     gi.setmodel (self, self->model);
  860.  
  861.     if (self->spawnflags & 1)
  862.     {
  863.         self->svflags |= SVF_NOCLIENT;
  864.         self->solid = SOLID_NOT;
  865.         self->use = func_explosive_spawn;
  866.     }
  867.     else
  868.     {
  869.         self->solid = SOLID_BSP;
  870.         if (self->targetname)
  871.             self->use = func_explosive_use;
  872.     }
  873.  
  874.     if (self->spawnflags & 2)
  875.         self->s.effects |= EF_ANIM_ALL;
  876.     if (self->spawnflags & 4)
  877.         self->s.effects |= EF_ANIM_ALLFAST;
  878.  
  879.     if (self->use != func_explosive_use)
  880.     {
  881.         if (!self->health)
  882.             self->health = 100;
  883.         self->die = func_explosive_explode;
  884.         self->takedamage = DAMAGE_YES;
  885.     }
  886.  
  887.     gi.linkentity (self);
  888. }
  889.  
  890.  
  891. /*QUAKED misc_explobox (0 .5 .8) (-16 -16 0) (16 16 40)
  892. Large exploding box.  You can override its mass (100),
  893. health (80), and dmg (150).
  894. */
  895.  
  896. void barrel_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  897.  
  898. {
  899.     float    ratio;
  900.     vec3_t    v;
  901.  
  902.     if ((!other->groundentity) || (other->groundentity == self))
  903.         return;
  904.  
  905.     ratio = (float)other->mass / (float)self->mass;
  906.     VectorSubtract (self->s.origin, other->s.origin, v);
  907.     M_walkmove (self, vectoyaw(v), 20 * ratio * FRAMETIME);
  908. }
  909.  
  910. void barrel_explode (edict_t *self)
  911. {
  912.     vec3_t    org;
  913.     float    spd;
  914.     vec3_t    save, size;
  915.  
  916.     T_RadiusDamage (self, self->activator, self->dmg, NULL, self->dmg+40, MOD_BARREL);
  917.  
  918.     VectorCopy (self->s.origin, save);
  919.     VectorMA (self->absmin, 0.5, self->size, self->s.origin);
  920.     VectorScale (self->size, 0.5, size);
  921.  
  922.     // a few big chunks
  923.     spd = 1.5 * (float)self->dmg / 200.0;
  924.     org[0] = self->s.origin[0] + crandom() * size[0];
  925.     org[1] = self->s.origin[1] + crandom() * size[1];
  926.     org[2] = self->s.origin[2] + crandom() * size[2];
  927.     ThrowDebris (self, "models/objects/debris1/tris.md2", spd, org);
  928.     org[0] = self->s.origin[0] + crandom() * size[0];
  929.     org[1] = self->s.origin[1] + crandom() * size[1];
  930.     org[2] = self->s.origin[2] + crandom() * size[2];
  931.     ThrowDebris (self, "models/objects/debris1/tris.md2", spd, org);
  932.  
  933.     // bottom corners
  934.     spd = 1.75 * (float)self->dmg / 200.0;
  935.     VectorCopy (self->absmin, org);
  936.     ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);
  937.     VectorCopy (self->absmin, org);
  938.     org[0] += self->size[0];
  939.     ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);
  940.     VectorCopy (self->absmin, org);
  941.     org[1] += self->size[1];
  942.     ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);
  943.     VectorCopy (self->absmin, org);
  944.     org[0] += self->size[0];
  945.     org[1] += self->size[1];
  946.     ThrowDebris (self, "models/objects/debris3/tris.md2", spd, org);
  947.  
  948.     // a bunch of little chunks
  949.     spd = 2 * self->dmg / 200;
  950.     org[0] = self->s.origin[0] + crandom() * size[0];
  951.     org[1] = self->s.origin[1] + crandom() * size[1];
  952.     org[2] = self->s.origin[2] + crandom() * size[2];
  953.     ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
  954.     org[0] = self->s.origin[0] + crandom() * size[0];
  955.     org[1] = self->s.origin[1] + crandom() * size[1];
  956.     org[2] = self->s.origin[2] + crandom() * size[2];
  957.     ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
  958.     org[0] = self->s.origin[0] + crandom() * size[0];
  959.     org[1] = self->s.origin[1] + crandom() * size[1];
  960.     org[2] = self->s.origin[2] + crandom() * size[2];
  961.     ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
  962.     org[0] = self->s.origin[0] + crandom() * size[0];
  963.     org[1] = self->s.origin[1] + crandom() * size[1];
  964.     org[2] = self->s.origin[2] + crandom() * size[2];
  965.     ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
  966.     org[0] = self->s.origin[0] + crandom() * size[0];
  967.     org[1] = self->s.origin[1] + crandom() * size[1];
  968.     org[2] = self->s.origin[2] + crandom() * size[2];
  969.     ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
  970.     org[0] = self->s.origin[0] + crandom() * size[0];
  971.     org[1] = self->s.origin[1] + crandom() * size[1];
  972.     org[2] = self->s.origin[2] + crandom() * size[2];
  973.     ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
  974.     org[0] = self->s.origin[0] + crandom() * size[0];
  975.     org[1] = self->s.origin[1] + crandom() * size[1];
  976.     org[2] = self->s.origin[2] + crandom() * size[2];
  977.     ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
  978.     org[0] = self->s.origin[0] + crandom() * size[0];
  979.     org[1] = self->s.origin[1] + crandom() * size[1];
  980.     org[2] = self->s.origin[2] + crandom() * size[2];
  981.     ThrowDebris (self, "models/objects/debris2/tris.md2", spd, org);
  982.  
  983.     VectorCopy (save, self->s.origin);
  984.     if (self->groundentity)
  985.         BecomeExplosion2 (self);
  986.     else
  987.         BecomeExplosion1 (self);
  988. }
  989.  
  990. void barrel_delay (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  991. {
  992.     self->takedamage = DAMAGE_NO;
  993.     self->nextthink = level.time + 2 * FRAMETIME;
  994.     self->think = barrel_explode;
  995.     self->activator = attacker;
  996. }
  997.  
  998. void SP_misc_explobox (edict_t *self)
  999. {
  1000.     if (deathmatch->value)
  1001.     {    // auto-remove for deathmatch
  1002.         G_FreeEdict (self);
  1003.         return;
  1004.     }
  1005.  
  1006.     gi.modelindex ("models/objects/debris1/tris.md2");
  1007.     gi.modelindex ("models/objects/debris2/tris.md2");
  1008.     gi.modelindex ("models/objects/debris3/tris.md2");
  1009.  
  1010.     self->solid = SOLID_BBOX;
  1011.     self->movetype = MOVETYPE_STEP;
  1012.  
  1013.     self->model = "models/objects/barrels/tris.md2";
  1014.     self->s.modelindex = gi.modelindex (self->model);
  1015.     VectorSet (self->mins, -16, -16, 0);
  1016.     VectorSet (self->maxs, 16, 16, 40);
  1017.  
  1018.     if (!self->mass)
  1019.         self->mass = 400;
  1020.     if (!self->health)
  1021.         self->health = 10;
  1022.     if (!self->dmg)
  1023.         self->dmg = 150;
  1024.  
  1025.     self->die = barrel_delay;
  1026.     self->takedamage = DAMAGE_YES;
  1027.     self->monsterinfo.aiflags = AI_NOSTEP;
  1028.  
  1029.     self->touch = barrel_touch;
  1030.  
  1031.     self->think = M_droptofloor;
  1032.     self->nextthink = level.time + 2 * FRAMETIME;
  1033.  
  1034.     gi.linkentity (self);
  1035. }
  1036.  
  1037.  
  1038. //
  1039. // miscellaneous specialty items
  1040. //
  1041.  
  1042. /*QUAKED misc_blackhole (1 .5 0) (-8 -8 -8) (8 8 8)
  1043. */
  1044.  
  1045. void misc_blackhole_use (edict_t *ent, edict_t *other, edict_t *activator)
  1046. {
  1047.     /*
  1048.     gi.WriteByte (svc_temp_entity);
  1049.     gi.WriteByte (TE_BOSSTPORT);
  1050.     gi.WritePosition (ent->s.origin);
  1051.     gi.multicast (ent->s.origin, MULTICAST_PVS);
  1052.     */
  1053.     G_FreeEdict (ent);
  1054. }
  1055.  
  1056. void misc_blackhole_think (edict_t *self)
  1057. {
  1058.     if (++self->s.frame < 19)
  1059.         self->nextthink = level.time + FRAMETIME;
  1060.     else
  1061.     {        
  1062.         self->s.frame = 0;
  1063.         self->nextthink = level.time + FRAMETIME;
  1064.     }
  1065. }
  1066.  
  1067. void SP_misc_blackhole (edict_t *ent)
  1068. {
  1069.     ent->movetype = MOVETYPE_NONE;
  1070.     ent->solid = SOLID_NOT;
  1071.     VectorSet (ent->mins, -64, -64, 0);
  1072.     VectorSet (ent->maxs, 64, 64, 8);
  1073.     ent->s.modelindex = gi.modelindex ("models/objects/black/tris.md2");
  1074.     ent->s.renderfx = RF_TRANSLUCENT;
  1075.     ent->use = misc_blackhole_use;
  1076.     ent->think = misc_blackhole_think;
  1077.     ent->nextthink = level.time + 2 * FRAMETIME;
  1078.     gi.linkentity (ent);
  1079. }
  1080.  
  1081. /*QUAKED misc_eastertank (1 .5 0) (-32 -32 -16) (32 32 32)
  1082. */
  1083.  
  1084. void misc_eastertank_think (edict_t *self)
  1085. {
  1086.     if (++self->s.frame < 293)
  1087.         self->nextthink = level.time + FRAMETIME;
  1088.     else
  1089.     {        
  1090.         self->s.frame = 254;
  1091.         self->nextthink = level.time + FRAMETIME;
  1092.     }
  1093. }
  1094.  
  1095. void SP_misc_eastertank (edict_t *ent)
  1096. {
  1097.     ent->movetype = MOVETYPE_NONE;
  1098.     ent->solid = SOLID_BBOX;
  1099.     VectorSet (ent->mins, -32, -32, -16);
  1100.     VectorSet (ent->maxs, 32, 32, 32);
  1101.     ent->s.modelindex = gi.modelindex ("models/monsters/tank/tris.md2");
  1102.     ent->s.frame = 254;
  1103.     ent->think = misc_eastertank_think;
  1104.     ent->nextthink = level.time + 2 * FRAMETIME;
  1105.     gi.linkentity (ent);
  1106. }
  1107.  
  1108. /*QUAKED misc_easterchick (1 .5 0) (-32 -32 0) (32 32 32)
  1109. */
  1110.  
  1111.  
  1112. void misc_easterchick_think (edict_t *self)
  1113. {
  1114.     if (++self->s.frame < 247)
  1115.         self->nextthink = level.time + FRAMETIME;
  1116.     else
  1117.     {        
  1118.         self->s.frame = 208;
  1119.         self->nextthink = level.time + FRAMETIME;
  1120.     }
  1121. }
  1122.  
  1123. void SP_misc_easterchick (edict_t *ent)
  1124. {
  1125.     ent->movetype = MOVETYPE_NONE;
  1126.     ent->solid = SOLID_BBOX;
  1127.     VectorSet (ent->mins, -32, -32, 0);
  1128.     VectorSet (ent->maxs, 32, 32, 32);
  1129.     ent->s.modelindex = gi.modelindex ("models/monsters/bitch/tris.md2");
  1130.     ent->s.frame = 208;
  1131.     ent->think = misc_easterchick_think;
  1132.     ent->nextthink = level.time + 2 * FRAMETIME;
  1133.     gi.linkentity (ent);
  1134. }
  1135.  
  1136. /*QUAKED misc_easterchick2 (1 .5 0) (-32 -32 0) (32 32 32)
  1137. */
  1138.  
  1139.  
  1140. void misc_easterchick2_think (edict_t *self)
  1141. {
  1142.     if (++self->s.frame < 287)
  1143.         self->nextthink = level.time + FRAMETIME;
  1144.     else
  1145.     {        
  1146.         self->s.frame = 248;
  1147.         self->nextthink = level.time + FRAMETIME;
  1148.     }
  1149. }
  1150.  
  1151. void SP_misc_easterchick2 (edict_t *ent)
  1152. {
  1153.     ent->movetype = MOVETYPE_NONE;
  1154.     ent->solid = SOLID_BBOX;
  1155.     VectorSet (ent->mins, -32, -32, 0);
  1156.     VectorSet (ent->maxs, 32, 32, 32);
  1157.     ent->s.modelindex = gi.modelindex ("models/monsters/bitch/tris.md2");
  1158.     ent->s.frame = 248;
  1159.     ent->think = misc_easterchick2_think;
  1160.     ent->nextthink = level.time + 2 * FRAMETIME;
  1161.     gi.linkentity (ent);
  1162. }
  1163.  
  1164.  
  1165. /*QUAKED monster_commander_body (1 .5 0) (-32 -32 0) (32 32 48)
  1166. Not really a monster, this is the Tank Commander's decapitated body.
  1167. There should be a item_commander_head that has this as it's target.
  1168. */
  1169.  
  1170. void commander_body_think (edict_t *self)
  1171. {
  1172.     if (++self->s.frame < 24)
  1173.         self->nextthink = level.time + FRAMETIME;
  1174.     else
  1175.         self->nextthink = 0;
  1176.  
  1177.     if (self->s.frame == 22)
  1178.         gi.sound (self, CHAN_BODY, gi.soundindex ("tank/thud.wav"), 1, ATTN_NORM, 0);
  1179. }
  1180.  
  1181. void commander_body_use (edict_t *self, edict_t *other, edict_t *activator)
  1182. {
  1183.     self->think = commander_body_think;
  1184.     self->nextthink = level.time + FRAMETIME;
  1185.     gi.sound (self, CHAN_BODY, gi.soundindex ("tank/pain.wav"), 1, ATTN_NORM, 0);
  1186. }
  1187.  
  1188. void commander_body_drop (edict_t *self)
  1189. {
  1190.     self->movetype = MOVETYPE_TOSS;
  1191.     self->s.origin[2] += 2;
  1192. }
  1193.  
  1194. void SP_monster_commander_body (edict_t *self)
  1195. {
  1196.     self->movetype = MOVETYPE_NONE;
  1197.     self->solid = SOLID_BBOX;
  1198.     self->model = "models/monsters/commandr/tris.md2";
  1199.     self->s.modelindex = gi.modelindex (self->model);
  1200.     VectorSet (self->mins, -32, -32, 0);
  1201.     VectorSet (self->maxs, 32, 32, 48);
  1202.     self->use = commander_body_use;
  1203.     self->takedamage = DAMAGE_YES;
  1204.     self->flags = FL_GODMODE;
  1205.     self->s.renderfx |= RF_FRAMELERP;
  1206.     gi.linkentity (self);
  1207.  
  1208.     gi.soundindex ("tank/thud.wav");
  1209.     gi.soundindex ("tank/pain.wav");
  1210.  
  1211.     self->think = commander_body_drop;
  1212.     self->nextthink = level.time + 5 * FRAMETIME;
  1213. }
  1214.  
  1215.  
  1216. /*QUAKED misc_banner (1 .5 0) (-4 -4 -4) (4 4 4)
  1217. The origin is the bottom of the banner.
  1218. The banner is 128 tall.
  1219. */
  1220. void misc_banner_think (edict_t *ent)
  1221. {
  1222.     ent->s.frame = (ent->s.frame + 1) % 16;
  1223.     ent->nextthink = level.time + FRAMETIME;
  1224. }
  1225.  
  1226. void SP_misc_banner (edict_t *ent)
  1227. {
  1228.     ent->movetype = MOVETYPE_NONE;
  1229.     ent->solid = SOLID_NOT;
  1230.     ent->s.modelindex = gi.modelindex ("models/objects/banner/tris.md2");
  1231.     ent->s.frame = rand() % 16;
  1232.     gi.linkentity (ent);
  1233.  
  1234.     ent->think = misc_banner_think;
  1235.     ent->nextthink = level.time + FRAMETIME;
  1236. }
  1237.  
  1238. /*QUAKED misc_deadsoldier (1 .5 0) (-16 -16 0) (16 16 16) ON_BACK ON_STOMACH BACK_DECAP FETAL_POS SIT_DECAP IMPALED
  1239. This is the dead player model. Comes in 6 exciting different poses!
  1240. */
  1241. void misc_deadsoldier_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  1242. {
  1243.     int        n;
  1244.  
  1245.     if (self->health > -80)
  1246.         return;
  1247.  
  1248.     gi.sound (self, CHAN_BODY, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
  1249.     for (n= 0; n < 4; n++)
  1250.         ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC, EF_GREENGIB);
  1251.     ThrowHead (self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC, EF_GREENGIB);
  1252. }
  1253.  
  1254. void SP_misc_deadsoldier (edict_t *ent)
  1255. {
  1256.     if (deathmatch->value)
  1257.     {    // auto-remove for deathmatch
  1258.         G_FreeEdict (ent);
  1259.         return;
  1260.     }
  1261.  
  1262.     ent->movetype = MOVETYPE_NONE;
  1263.     ent->solid = SOLID_BBOX;
  1264.     ent->s.modelindex=gi.modelindex ("models/deadbods/dude/tris.md2");
  1265.  
  1266.     // Defaults to frame 0
  1267.     if (ent->spawnflags & 2)
  1268.         ent->s.frame = 1;
  1269.     else if (ent->spawnflags & 4)
  1270.         ent->s.frame = 2;
  1271.     else if (ent->spawnflags & 8)
  1272.         ent->s.frame = 3;
  1273.     else if (ent->spawnflags & 16)
  1274.         ent->s.frame = 4;
  1275.     else if (ent->spawnflags & 32)
  1276.         ent->s.frame = 5;
  1277.     else
  1278.         ent->s.frame = 0;
  1279.  
  1280.     VectorSet (ent->mins, -16, -16, 0);
  1281.     VectorSet (ent->maxs, 16, 16, 16);
  1282.     ent->deadflag = DEAD_DEAD;
  1283.     ent->takedamage = DAMAGE_YES;
  1284.     ent->svflags |= SVF_MONSTER|SVF_DEADMONSTER;
  1285.     ent->die = misc_deadsoldier_die;
  1286.     ent->monsterinfo.aiflags |= AI_GOOD_GUY;
  1287.  
  1288.     gi.linkentity (ent);
  1289. }
  1290.  
  1291. /*QUAKED misc_viper (1 .5 0) (-16 -16 0) (16 16 32)
  1292. This is the Viper for the flyby bombing.
  1293. It is trigger_spawned, so you must have something use it for it to show up.
  1294. There must be a path for it to follow once it is activated.
  1295.  
  1296. "speed"        How fast the Viper should fly
  1297. */
  1298.  
  1299. extern void train_use (edict_t *self, edict_t *other, edict_t *activator);
  1300. extern void func_train_find (edict_t *self);
  1301.  
  1302. void misc_viper_use  (edict_t *self, edict_t *other, edict_t *activator)
  1303. {
  1304.     self->svflags &= ~SVF_NOCLIENT;
  1305.     self->use = train_use;
  1306.     train_use (self, other, activator);
  1307. }
  1308.  
  1309. void SP_misc_viper (edict_t *ent)
  1310. {
  1311.     if (!ent->target)
  1312.     {
  1313.         gi.dprintf ("misc_viper without a target at %s\n", vtos(ent->absmin));
  1314.         G_FreeEdict (ent);
  1315.         return;
  1316.     }
  1317.  
  1318.     if (!ent->speed)
  1319.         ent->speed = 300;
  1320.  
  1321.     ent->movetype = MOVETYPE_PUSH;
  1322.     ent->solid = SOLID_NOT;
  1323.     ent->s.modelindex = gi.modelindex ("models/ships/viper/tris.md2");
  1324.     VectorSet (ent->mins, -16, -16, 0);
  1325.     VectorSet (ent->maxs, 16, 16, 32);
  1326.  
  1327.     ent->think = func_train_find;
  1328.     ent->nextthink = level.time + FRAMETIME;
  1329.     ent->use = misc_viper_use;
  1330.     ent->svflags |= SVF_NOCLIENT;
  1331.     ent->moveinfo.accel = ent->moveinfo.decel = ent->moveinfo.speed = ent->speed;
  1332.  
  1333.     gi.linkentity (ent);
  1334. }
  1335.  
  1336.  
  1337. /*QUAKED misc_bigviper (1 .5 0) (-176 -120 -24) (176 120 72) 
  1338. This is a large stationary viper as seen in Paul's intro
  1339. */
  1340. void SP_misc_bigviper (edict_t *ent)
  1341. {
  1342.     ent->movetype = MOVETYPE_NONE;
  1343.     ent->solid = SOLID_BBOX;
  1344.     VectorSet (ent->mins, -176, -120, -24);
  1345.     VectorSet (ent->maxs, 176, 120, 72);
  1346.     ent->s.modelindex = gi.modelindex ("models/ships/bigviper/tris.md2");
  1347.     gi.linkentity (ent);
  1348. }
  1349.  
  1350.  
  1351. /*QUAKED misc_viper_bomb (1 0 0) (-8 -8 -8) (8 8 8)
  1352. "dmg"    how much boom should the bomb make?
  1353. */
  1354. void misc_viper_bomb_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  1355. {
  1356.     G_UseTargets (self, self->activator);
  1357.  
  1358.     self->s.origin[2] = self->absmin[2] + 1;
  1359.     T_RadiusDamage (self, self, self->dmg, NULL, self->dmg+40, MOD_BOMB);
  1360.     BecomeExplosion2 (self);
  1361. }
  1362.  
  1363. void misc_viper_bomb_prethink (edict_t *self)
  1364. {
  1365.     vec3_t    v;
  1366.     float    diff;
  1367.  
  1368.     self->groundentity = NULL;
  1369.  
  1370.     diff = self->timestamp - level.time;
  1371.     if (diff < -1.0)
  1372.         diff = -1.0;
  1373.  
  1374.     VectorScale (self->moveinfo.dir, 1.0 + diff, v);
  1375.     v[2] = diff;
  1376.  
  1377.     diff = self->s.angles[2];
  1378.     vectoangles (v, self->s.angles);
  1379.     self->s.angles[2] = diff + 10;
  1380. }
  1381.  
  1382. void misc_viper_bomb_use (edict_t *self, edict_t *other, edict_t *activator)
  1383. {
  1384.     edict_t    *viper;
  1385.  
  1386.     self->solid = SOLID_BBOX;
  1387.     self->svflags &= ~SVF_NOCLIENT;
  1388.     self->s.effects |= EF_ROCKET;
  1389.     self->use = NULL;
  1390.     self->movetype = MOVETYPE_TOSS;
  1391.     self->prethink = misc_viper_bomb_prethink;
  1392.     self->touch = misc_viper_bomb_touch;
  1393.     self->activator = activator;
  1394.  
  1395.     viper = G_Find (NULL, FOFS(classname), "misc_viper");
  1396.     VectorScale (viper->moveinfo.dir, viper->moveinfo.speed, self->velocity);
  1397.  
  1398.     self->timestamp = level.time;
  1399.     VectorCopy (viper->moveinfo.dir, self->moveinfo.dir);
  1400. }
  1401.  
  1402. void SP_misc_viper_bomb (edict_t *self)
  1403. {
  1404.     self->movetype = MOVETYPE_NONE;
  1405.     self->solid = SOLID_NOT;
  1406.     VectorSet (self->mins, -8, -8, -8);
  1407.     VectorSet (self->maxs, 8, 8, 8);
  1408.  
  1409.     self->s.modelindex = gi.modelindex ("models/objects/bomb/tris.md2");
  1410.  
  1411.     if (!self->dmg)
  1412.         self->dmg = 1000;
  1413.  
  1414.     self->use = misc_viper_bomb_use;
  1415.     self->svflags |= SVF_NOCLIENT;
  1416.  
  1417.     gi.linkentity (self);
  1418. }
  1419.  
  1420.  
  1421. /*QUAKED misc_strogg_ship (1 .5 0) (-16 -16 0) (16 16 32)
  1422. This is a Storgg ship for the flybys.
  1423. It is trigger_spawned, so you must have something use it for it to show up.
  1424. There must be a path for it to follow once it is activated.
  1425.  
  1426. "speed"        How fast it should fly
  1427. */
  1428.  
  1429. extern void train_use (edict_t *self, edict_t *other, edict_t *activator);
  1430. extern void func_train_find (edict_t *self);
  1431.  
  1432. void misc_strogg_ship_use  (edict_t *self, edict_t *other, edict_t *activator)
  1433. {
  1434.     self->svflags &= ~SVF_NOCLIENT;
  1435.     self->use = train_use;
  1436.     train_use (self, other, activator);
  1437. }
  1438.  
  1439. void SP_misc_leader_ship (edict_t *ent)
  1440. {
  1441.     if (!ent->target)
  1442.     {
  1443.         gi.dprintf ("%s without a target at %s\n", ent->classname, vtos(ent->absmin));
  1444.         G_FreeEdict (ent);
  1445.         return;
  1446.     }
  1447.  
  1448.     if (!ent->speed)
  1449.         ent->speed = 300;
  1450.  
  1451.     ent->movetype = MOVETYPE_PUSH;
  1452.     ent->solid = SOLID_NOT;
  1453.     ent->s.modelindex = gi.modelindex ("models/ships/leadership/tris.md2");
  1454.     VectorSet (ent->mins, -16, -16, 0);
  1455.     VectorSet (ent->maxs, 16, 16, 32);
  1456.  
  1457.     ent->think = func_train_find;
  1458.     ent->nextthink = level.time + FRAMETIME;
  1459.     ent->use = misc_strogg_ship_use;
  1460.     ent->svflags |= SVF_NOCLIENT;
  1461.     ent->moveinfo.accel = ent->moveinfo.decel = ent->moveinfo.speed = ent->speed;
  1462.     ent->s.effects |= EF_SHIPEXHAUST; //change this!
  1463.     gi.linkentity (ent);
  1464. }
  1465.  
  1466.  
  1467. /*QUAKED misc_satellite_dish (1 .5 0) (-64 -64 0) (64 64 128)
  1468. */
  1469. void misc_satellite_dish_think (edict_t *self)
  1470. {
  1471.     self->s.frame++;
  1472.     if (self->s.frame < 38)
  1473.         self->nextthink = level.time + FRAMETIME;
  1474. }
  1475.  
  1476. void misc_satellite_dish_use (edict_t *self, edict_t *other, edict_t *activator)
  1477. {
  1478.     self->s.frame = 0;
  1479.     self->think = misc_satellite_dish_think;
  1480.     self->nextthink = level.time + FRAMETIME;
  1481. }
  1482.  
  1483. void SP_misc_satellite_dish (edict_t *ent)
  1484. {
  1485.     ent->movetype = MOVETYPE_NONE;
  1486.     ent->solid = SOLID_BBOX;
  1487.     VectorSet (ent->mins, -64, -64, 0);
  1488.     VectorSet (ent->maxs, 64, 64, 128);
  1489.     ent->s.modelindex = gi.modelindex ("models/objects/satellite/tris.md2");
  1490.     ent->use = misc_satellite_dish_use;
  1491.     gi.linkentity (ent);
  1492. }
  1493.  
  1494.  
  1495. /*QUAKED light_mine1 (0 1 0) (-2 -2 -12) (2 2 12)
  1496. */
  1497. void SP_light_mine1 (edict_t *ent)
  1498. {
  1499.     ent->movetype = MOVETYPE_NONE;
  1500.     ent->solid = SOLID_BBOX;
  1501.     ent->s.modelindex = gi.modelindex ("models/objects/minelite/light1/tris.md2");
  1502.     gi.linkentity (ent);
  1503. }
  1504.  
  1505.  
  1506. /*QUAKED light_mine2 (0 1 0) (-2 -2 -12) (2 2 12)
  1507. */
  1508. void SP_light_mine2 (edict_t *ent)
  1509. {
  1510.     ent->movetype = MOVETYPE_NONE;
  1511.     ent->solid = SOLID_BBOX;
  1512.     ent->s.modelindex = gi.modelindex ("models/objects/minelite/light2/tris.md2");
  1513.     gi.linkentity (ent);
  1514. }
  1515.  
  1516.  
  1517. /*QUAKED misc_gib_arm (1 0 0) (-8 -8 -8) (8 8 8)
  1518. Intended for use with the target_spawner
  1519. */
  1520. void SP_misc_gib_arm (edict_t *ent)
  1521. {
  1522.     gi.setmodel (ent, "models/objects/gibs/arm/tris.md2");
  1523.     ent->solid = SOLID_NOT;
  1524.     ent->s.effects |= EF_GIB;
  1525.     ent->takedamage = DAMAGE_YES;
  1526.     ent->die = gib_die;
  1527.     ent->movetype = MOVETYPE_TOSS;
  1528.     ent->svflags |= SVF_MONSTER;
  1529.     ent->deadflag = DEAD_DEAD;
  1530.     ent->avelocity[0] = random()*200;
  1531.     ent->avelocity[1] = random()*200;
  1532.     ent->avelocity[2] = random()*200;
  1533.     ent->think = G_FreeEdict;
  1534.     ent->nextthink = level.time + 30;
  1535.     gi.linkentity (ent);
  1536. }
  1537.  
  1538. /*QUAKED misc_gib_leg (1 0 0) (-8 -8 -8) (8 8 8)
  1539. Intended for use with the target_spawner
  1540. */
  1541. void SP_misc_gib_leg (edict_t *ent)
  1542. {
  1543.     gi.setmodel (ent, "models/objects/gibs/leg/tris.md2");
  1544.     ent->solid = SOLID_NOT;
  1545.     ent->s.effects |= EF_GIB;
  1546.     ent->takedamage = DAMAGE_YES;
  1547.     ent->die = gib_die;
  1548.     ent->movetype = MOVETYPE_TOSS;
  1549.     ent->svflags |= SVF_MONSTER;
  1550.     ent->deadflag = DEAD_DEAD;
  1551.     ent->avelocity[0] = random()*200;
  1552.     ent->avelocity[1] = random()*200;
  1553.     ent->avelocity[2] = random()*200;
  1554.     ent->think = G_FreeEdict;
  1555.     ent->nextthink = level.time + 30;
  1556.     gi.linkentity (ent);
  1557. }
  1558.  
  1559. /*QUAKED misc_gib_head (1 0 0) (-8 -8 -8) (8 8 8)
  1560. Intended for use with the target_spawner
  1561. */
  1562. void SP_misc_gib_head (edict_t *ent)
  1563. {
  1564.     gi.setmodel (ent, "models/objects/gibs/head/tris.md2");
  1565.     ent->solid = SOLID_NOT;
  1566.     ent->s.effects |= EF_GIB;
  1567.     ent->takedamage = DAMAGE_YES;
  1568.     ent->die = gib_die;
  1569.     ent->movetype = MOVETYPE_TOSS;
  1570.     ent->svflags |= SVF_MONSTER;
  1571.     ent->deadflag = DEAD_DEAD;
  1572.     ent->avelocity[0] = random()*200;
  1573.     ent->avelocity[1] = random()*200;
  1574.     ent->avelocity[2] = random()*200;
  1575.     ent->think = G_FreeEdict;
  1576.     ent->nextthink = level.time + 30;
  1577.     gi.linkentity (ent);
  1578. }
  1579.  
  1580. //=====================================================
  1581.  
  1582. /*QUAKED target_character (0 0 1) ?
  1583. used with target_string (must be on same "team")
  1584. "count" is position in the string (starts at 1)
  1585. */
  1586.  
  1587. void SP_target_character (edict_t *self)
  1588. {
  1589.     self->movetype = MOVETYPE_PUSH;
  1590.     gi.setmodel (self, self->model);
  1591.     self->solid = SOLID_BSP;
  1592.     self->s.frame = 12;
  1593.     gi.linkentity (self);
  1594.     return;
  1595. }
  1596.  
  1597.  
  1598. /*QUAKED target_string (0 0 1) (-8 -8 -8) (8 8 8)
  1599. */
  1600.  
  1601. void target_string_use (edict_t *self, edict_t *other, edict_t *activator)
  1602. {
  1603.     edict_t *e;
  1604.     int        n, l;
  1605.     char    c;
  1606.  
  1607.     l = strlen(self->message);
  1608.     for (e = self->teammaster; e; e = e->teamchain)
  1609.     {
  1610.         if (!e->count)
  1611.             continue;
  1612.         n = e->count - 1;
  1613.         if (n > l)
  1614.         {
  1615.             e->s.frame = 12;
  1616.             continue;
  1617.         }
  1618.  
  1619.         c = self->message[n];
  1620.         if (c >= '0' && c <= '9')
  1621.             e->s.frame = c - '0';
  1622.         else if (c == '-')
  1623.             e->s.frame = 10;
  1624.         else if (c == ':')
  1625.             e->s.frame = 11;
  1626.         else
  1627.             e->s.frame = 12;
  1628.     }
  1629. }
  1630.  
  1631. void SP_target_string (edict_t *self)
  1632. {
  1633.     if (!self->message)
  1634.         self->message = "";
  1635.     self->use = target_string_use;
  1636. }
  1637.  
  1638.  
  1639. /*QUAKED func_clock (0 0 1) (-8 -8 -8) (8 8 8) TIMER_UP TIMER_DOWN START_OFF MULTI_USE
  1640. target a target_string with this
  1641.  
  1642. The default is to be a time of day clock
  1643.  
  1644. TIMER_UP and TIMER_DOWN run for "count" seconds and the fire "pathtarget"
  1645. If START_OFF, this entity must be used before it starts
  1646.  
  1647. "style"        0 "xx"
  1648.             1 "xx:xx"
  1649.             2 "xx:xx:xx"
  1650. */
  1651.  
  1652. #define    CLOCK_MESSAGE_SIZE    16
  1653.  
  1654. // don't let field width of any clock messages change, or it
  1655. // could cause an overwrite after a game load
  1656.  
  1657. static void func_clock_reset (edict_t *self)
  1658. {
  1659.     self->activator = NULL;
  1660.     if (self->spawnflags & 1)
  1661.     {
  1662.         self->health = 0;
  1663.         self->wait = self->count;
  1664.     }
  1665.     else if (self->spawnflags & 2)
  1666.     {
  1667.         self->health = self->count;
  1668.         self->wait = 0;
  1669.     }
  1670. }
  1671.  
  1672. static void func_clock_format_countdown (edict_t *self)
  1673. {
  1674.     if (self->style == 0)
  1675.     {
  1676.         Com_sprintf (self->message, CLOCK_MESSAGE_SIZE, "%2i", self->health);
  1677.         return;
  1678.     }
  1679.  
  1680.     if (self->style == 1)
  1681.     {
  1682.         Com_sprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i", self->health / 60, self->health % 60);
  1683.         if (self->message[3] == ' ')
  1684.             self->message[3] = '0';
  1685.         return;
  1686.     }
  1687.  
  1688.     if (self->style == 2)
  1689.     {
  1690.         Com_sprintf(self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", self->health / 3600, (self->health - (self->health / 3600) * 3600) / 60, self->health % 60);
  1691.         if (self->message[3] == ' ')
  1692.             self->message[3] = '0';
  1693.         if (self->message[6] == ' ')
  1694.             self->message[6] = '0';
  1695.         return;
  1696.     }
  1697. }
  1698.  
  1699. void func_clock_think (edict_t *self)
  1700. {
  1701.     if (!self->enemy)
  1702.     {
  1703.         self->enemy = G_Find (NULL, FOFS(targetname), self->target);
  1704.         if (!self->enemy)
  1705.             return;
  1706.     }
  1707.  
  1708.     if (self->spawnflags & 1)
  1709.     {
  1710.         func_clock_format_countdown (self);
  1711.         self->health++;
  1712.     }
  1713.     else if (self->spawnflags & 2)
  1714.     {
  1715.         func_clock_format_countdown (self);
  1716.         self->health--;
  1717.     }
  1718.     else
  1719.     {
  1720.         struct tm    *ltime;
  1721.         time_t        gmtime;
  1722.  
  1723.         time(&gmtime);
  1724.         ltime = localtime(&gmtime);
  1725.         Com_sprintf (self->message, CLOCK_MESSAGE_SIZE, "%2i:%2i:%2i", ltime->tm_hour, ltime->tm_min, ltime->tm_sec);
  1726.         if (self->message[3] == ' ')
  1727.             self->message[3] = '0';
  1728.         if (self->message[6] == ' ')
  1729.             self->message[6] = '0';
  1730.     }
  1731.  
  1732.     self->enemy->message = self->message;
  1733.     self->enemy->use (self->enemy, self, self);
  1734.  
  1735.     if (((self->spawnflags & 1) && (self->health > self->wait)) ||
  1736.         ((self->spawnflags & 2) && (self->health < self->wait)))
  1737.     {
  1738.         if (self->pathtarget)
  1739.         {
  1740.             char *savetarget;
  1741.             char *savemessage;
  1742.  
  1743.             savetarget = self->target;
  1744.             savemessage = self->message;
  1745.             self->target = self->pathtarget;
  1746.             self->message = NULL;
  1747.             G_UseTargets (self, self->activator);
  1748.             self->target = savetarget;
  1749.             self->message = savemessage;
  1750.         }
  1751.  
  1752.         if (!(self->spawnflags & 8))
  1753.             return;
  1754.  
  1755.         func_clock_reset (self);
  1756.  
  1757.         if (self->spawnflags & 4)
  1758.             return;
  1759.     }
  1760.  
  1761.     self->nextthink = level.time + 1;
  1762. }
  1763.  
  1764. void func_clock_use (edict_t *self, edict_t *other, edict_t *activator)
  1765. {
  1766.     if (!(self->spawnflags & 8))
  1767.         self->use = NULL;
  1768.     if (self->activator)
  1769.         return;
  1770.     self->activator = activator;
  1771.     self->think (self);
  1772. }
  1773.  
  1774. void SP_func_clock (edict_t *self)
  1775. {
  1776.     if (!self->target)
  1777.     {
  1778.         gi.dprintf("%s with no target at %s\n", self->classname, vtos(self->s.origin));
  1779.         G_FreeEdict (self);
  1780.         return;
  1781.     }
  1782.  
  1783.     if ((self->spawnflags & 2) && (!self->count))
  1784.     {
  1785.         gi.dprintf("%s with no count at %s\n", self->classname, vtos(self->s.origin));
  1786.         G_FreeEdict (self);
  1787.         return;
  1788.     }
  1789.  
  1790.     if ((self->spawnflags & 1) && (!self->count))
  1791.         self->count = 60*60;;
  1792.  
  1793.     func_clock_reset (self);
  1794.  
  1795.     self->message = gi.TagMalloc (CLOCK_MESSAGE_SIZE, TAG_LEVEL);
  1796.  
  1797.     self->think = func_clock_think;
  1798.  
  1799.     if (self->spawnflags & 4)
  1800.         self->use = func_clock_use;
  1801.     else
  1802.         self->nextthink = level.time + 1;
  1803. }
  1804.  
  1805. //=================================================================================
  1806.  
  1807. void teleporter_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
  1808. {
  1809.     edict_t        *dest;
  1810.     int            i;
  1811.  
  1812.     if (!other->client)
  1813.         return;
  1814.     dest = G_Find (NULL, FOFS(targetname), self->target);
  1815.     if (!dest)
  1816.     {
  1817.         gi.dprintf ("Couldn't find destination\n");
  1818.         return;
  1819.     }
  1820.  
  1821.     // unlink to make sure it can't possibly interfere with KillBox
  1822.     gi.unlinkentity (other);
  1823.  
  1824.     VectorCopy (dest->s.origin, other->s.origin);
  1825.     VectorCopy (dest->s.origin, other->s.old_origin);
  1826.     other->s.origin[2] += 10;
  1827.  
  1828.     // clear the velocity and hold them in place briefly
  1829.     VectorClear (other->velocity);
  1830.     other->client->ps.pmove.pm_time = 160>>3;        // hold time
  1831.     other->client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT;
  1832.  
  1833.     // draw the teleport splash at source and on the player
  1834.     self->owner->s.event = EV_PLAYER_TELEPORT;
  1835.     other->s.event = EV_PLAYER_TELEPORT;
  1836.  
  1837.     // set angles
  1838.     for (i=0 ; i<3 ; i++)
  1839.     {
  1840.         other->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(dest->s.angles[i] - other->client->resp.cmd_angles[i]);
  1841.     }
  1842.  
  1843.     VectorClear (other->s.angles);
  1844.     VectorClear (other->client->ps.viewangles);
  1845.     VectorClear (other->client->v_angle);
  1846.  
  1847.     // kill anything at the destination
  1848.     KillBox (other);
  1849.  
  1850.     gi.linkentity (other);
  1851. }
  1852.  
  1853. /*QUAKED misc_teleporter (1 0 0) (-32 -32 -24) (32 32 -16)
  1854. Stepping onto this disc will teleport players to the targeted misc_teleporter_dest object.
  1855. */
  1856. void SP_misc_teleporter (edict_t *ent)
  1857. {
  1858.     edict_t        *trig;
  1859.  
  1860.     if (!ent->target)
  1861.     {
  1862.         gi.dprintf ("teleporter without a target.\n");
  1863.         G_FreeEdict (ent);
  1864.         return;
  1865.     }
  1866.  
  1867.     gi.setmodel (ent, "models/objects/dmspot/tris.md2");
  1868.     ent->s.skinnum = 1;
  1869.     ent->s.effects = EF_TELEPORTER;
  1870.     ent->s.sound = gi.soundindex ("world/amb10.wav");
  1871.     ent->solid = SOLID_BBOX;
  1872.  
  1873.     VectorSet (ent->mins, -32, -32, -24);
  1874.     VectorSet (ent->maxs, 32, 32, -16);
  1875.     gi.linkentity (ent);
  1876.  
  1877.     trig = G_Spawn ();
  1878.     trig->touch = teleporter_touch;
  1879.     trig->solid = SOLID_TRIGGER;
  1880.     trig->target = ent->target;
  1881.     trig->owner = ent;
  1882.     VectorCopy (ent->s.origin, trig->s.origin);
  1883.     VectorSet (trig->mins, -8, -8, 8);
  1884.     VectorSet (trig->maxs, 8, 8, 24);
  1885.     gi.linkentity (trig);
  1886.     
  1887. }
  1888.  
  1889. /*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)
  1890. Point teleporters at these.
  1891. */
  1892. void SP_misc_teleporter_dest (edict_t *ent)
  1893. {
  1894.     gi.setmodel (ent, "models/objects/dmspot/tris.md2");
  1895.     ent->s.skinnum = 0;
  1896.     ent->solid = SOLID_BBOX;
  1897. //    ent->s.effects |= EF_FLIES;
  1898.     VectorSet (ent->mins, -32, -32, -24);
  1899.     VectorSet (ent->maxs, 32, 32, -16);
  1900.     gi.linkentity (ent);
  1901. }
  1902.  
  1903. void misc_skele_think (edict_t *ent)
  1904. {
  1905.     ent->s.frame = (ent->s.frame + 1) % 26;
  1906.     ent->nextthink = level.time + FRAMETIME;
  1907. }
  1908.  
  1909. void SP_misc_skele (edict_t *ent)
  1910. {
  1911.     ent->movetype = MOVETYPE_NONE;
  1912.     ent->solid = SOLID_NOT;
  1913.     ent->s.modelindex = gi.modelindex ("models/objects/skele/tris.md2");
  1914.  
  1915.     ent->solid = SOLID_BBOX;
  1916.     ent->s.effects = EF_COLOR_SHELL;
  1917.  
  1918.     if (ent->spawnflags & 1)
  1919.     {
  1920.         ent->s.skinnum = 1;
  1921.         ent->s.renderfx = RF_GLOW | RF_FULLBRIGHT;
  1922.     }
  1923.     else 
  1924.     {
  1925.         ent->s.skinnum = 0;
  1926.         ent->s.renderfx = (RF_SHELL_RED | RF_FULLBRIGHT | RF_GLOW);
  1927.     }
  1928.  
  1929.     VectorSet (ent->mins, -16, -16, 0);
  1930.     VectorSet (ent->maxs, 16, 16, 56);
  1931.  
  1932.     ent->s.frame = rand() % 26;
  1933.     gi.linkentity (ent);
  1934.  
  1935.     ent->think = misc_skele_think;
  1936.     ent->nextthink = level.time + FRAMETIME;
  1937. }
  1938.  
  1939. void SP_misc_skele_sit (edict_t *ent)
  1940. {
  1941.     ent->movetype = MOVETYPE_NONE;
  1942.     ent->solid = SOLID_NOT;
  1943.     ent->s.modelindex = gi.modelindex ("models/objects/skele/tris2.md2");
  1944.  
  1945.     ent->solid = SOLID_BBOX;
  1946.     ent->s.effects = EF_COLOR_SHELL;
  1947.  
  1948.     if (ent->spawnflags & 1)
  1949.     {
  1950.         ent->s.skinnum = 1;
  1951.         ent->s.renderfx = RF_GLOW | RF_FULLBRIGHT;
  1952.     }
  1953.     else 
  1954.     {
  1955.         ent->s.skinnum = 0;
  1956.         ent->s.renderfx = (RF_SHELL_RED | RF_FULLBRIGHT | RF_GLOW);
  1957.     }
  1958.     VectorSet (ent->mins, -16, -16, 0);
  1959.     VectorSet (ent->maxs, 16, 16, 56);
  1960.  
  1961.     ent->s.frame = rand() % 26;
  1962.     gi.linkentity (ent);
  1963.  
  1964.     ent->think = misc_skele_think;
  1965.     ent->nextthink = level.time + FRAMETIME;
  1966. }
  1967.  
  1968. void SP_misc_skele_lie (edict_t *ent)
  1969. {
  1970.     ent->movetype = MOVETYPE_NONE;
  1971.     ent->solid = SOLID_NOT;
  1972.     ent->s.modelindex = gi.modelindex ("models/objects/skele/tris3.md2");
  1973.  
  1974.     ent->solid = SOLID_BBOX;
  1975.     ent->s.effects = EF_COLOR_SHELL;
  1976.  
  1977.     if (ent->spawnflags & 1)
  1978.     {
  1979.         ent->s.skinnum = 1;
  1980.         ent->s.renderfx = RF_GLOW | RF_FULLBRIGHT;
  1981.     }
  1982.     else 
  1983.     {
  1984.         ent->s.skinnum = 0;
  1985.         ent->s.renderfx = (RF_SHELL_RED | RF_FULLBRIGHT | RF_GLOW);
  1986.     }
  1987.  
  1988.     VectorSet (ent->mins, -16, -16, 0);
  1989.     VectorSet (ent->maxs, 16, 16, 24);
  1990.  
  1991.     ent->s.frame = rand() % 26;
  1992.     gi.linkentity (ent);
  1993.  
  1994.     ent->think = misc_skele_think;
  1995.     ent->nextthink = level.time + FRAMETIME;
  1996. }
  1997.  
  1998. void SP_misc_skele_blood (edict_t *ent)
  1999. {
  2000.     ent->movetype = MOVETYPE_NONE;
  2001.     ent->solid = SOLID_NOT;
  2002.  
  2003.     if (ent->spawnflags & 1)
  2004.         ent->s.modelindex = gi.modelindex ("sprites/blood1.sp2"); // red
  2005.     else
  2006.         ent->s.modelindex = gi.modelindex ("sprites/blood2.sp2"); // green
  2007.  
  2008.     ent->s.renderfx = RF_GLOW | RF_FULLBRIGHT;
  2009.     VectorSet (ent->mins, 0, 0, 16);
  2010.     VectorSet (ent->maxs, 0, 0, 16);
  2011.  
  2012.     ent->s.frame = 0;
  2013.     gi.linkentity (ent);
  2014.  
  2015.     ent->think = NULL;
  2016. }
  2017.  
  2018. void misc_vortex_think (edict_t *self)
  2019. {
  2020.     vec3_t start;
  2021.     int n;
  2022.     
  2023.     VectorCopy (self->s.origin, start);
  2024.     
  2025.     for (n = 0; n < 7; n++)
  2026.     {
  2027.         start[2] = start[2] + 36;
  2028.         gi.WriteByte (svc_temp_entity);
  2029.         gi.WriteByte (TE_SMART_MUZZLEFLASH);
  2030.         gi.WritePosition (start);
  2031.         gi.multicast (start, MULTICAST_PVS);
  2032.     }
  2033.     
  2034.     self->nextthink = level.time + 1;
  2035. }
  2036.  
  2037. void SP_misc_vortex (edict_t *ent)
  2038. {
  2039.     ent->movetype = MOVETYPE_NONE;
  2040.     ent->solid = SOLID_NOT;
  2041.     ent->s.modelindex = 0;
  2042.     ent->s.renderfx = RF_FULLBRIGHT;
  2043.  
  2044.     VectorSet (ent->mins, -8, -8, 0);
  2045.     VectorSet (ent->maxs, 8, 8, 8);
  2046.     
  2047.     gi.linkentity (ent);
  2048.  
  2049.     ent->think = misc_vortex_think;
  2050.     ent->nextthink = level.time + 1;
  2051. }
  2052.  
  2053. void SP_misc_grass (edict_t *ent)
  2054. {
  2055.     
  2056.     ent->movetype = MOVETYPE_NONE;
  2057.     ent->solid = SOLID_NOT;
  2058.  
  2059.     if(random() < 0.4)
  2060.         ent->s.modelindex = gi.modelindex ("models/objects/grass/tris.md2");
  2061.     else if(random() < 0.5)
  2062.         ent->s.modelindex = gi.modelindex ("models/objects/grass_med/tris.md2");
  2063.     else
  2064.         ent->s.modelindex = gi.modelindex ("models/objects/grass_short/tris.md2");
  2065.  
  2066.     VectorSet (ent->mins, -16, -16, 0);
  2067.     VectorSet (ent->maxs, 16, 16, 8);
  2068.  
  2069.     gi.linkentity (ent);
  2070.     
  2071.     ent->think = NULL;
  2072.     
  2073.     M_droptofloor (ent);
  2074. }
  2075. void misc_tube_think (edict_t *ent)
  2076. {
  2077.     ent->s.frame = (ent->s.frame + 1) % 18;
  2078.     ent->nextthink = level.time + FRAMETIME;
  2079. }
  2080. void SP_misc_tube (edict_t *ent)
  2081. {
  2082.     ent->movetype = MOVETYPE_NONE;
  2083.     ent->solid = SOLID_NOT;
  2084.     ent->s.modelindex = gi.modelindex ("models/objects/tube/tris.md2");
  2085.  
  2086.     VectorSet (ent->mins, -16, -16, -8);
  2087.     VectorSet (ent->maxs, 16, 16, 56);
  2088.  
  2089.     ent->s.frame = rand() % 18;
  2090.     gi.linkentity (ent);
  2091.  
  2092.     ent->think = misc_tube_think;
  2093.     ent->nextthink = level.time + FRAMETIME;
  2094.  
  2095.     M_droptofloor (ent);
  2096. }
  2097. void SP_misc_patient (edict_t *ent)
  2098. {
  2099.     
  2100.     ent->movetype = MOVETYPE_NONE;
  2101.     ent->solid = SOLID_NOT;
  2102.  
  2103.     if(ent->spawnflags & 1)
  2104.         ent->s.modelindex = gi.modelindex ("models/npc/redneck_dead/tris.md2");
  2105.     else
  2106.         ent->s.modelindex = gi.modelindex ("models/objects/patient/tris.md2");
  2107.  
  2108.     VectorSet (ent->mins, -16, -16, 0);
  2109.     VectorSet (ent->maxs, 16, 16, 8);
  2110.  
  2111.     gi.linkentity (ent);
  2112.     
  2113.     ent->think = NULL;
  2114.     
  2115.     M_droptofloor (ent);
  2116. }
  2117. void SP_misc_head (edict_t *ent)
  2118. {
  2119.     
  2120.     ent->movetype = MOVETYPE_NONE;
  2121.     ent->solid = SOLID_NOT;
  2122.  
  2123.     
  2124.     ent->s.modelindex = gi.modelindex ("models/objects/head/tris.md2");
  2125.  
  2126.     VectorSet (ent->mins, -16, -16, 0);
  2127.     VectorSet (ent->maxs, 16, 16, 16);
  2128.  
  2129.     gi.linkentity (ent);
  2130.      
  2131.     ent->think = NULL;
  2132.     
  2133.     M_droptofloor (ent);
  2134. }